import numpy as np
import  pandas as pd
import matplotlib.pyplot as plt

class PCA:
    """
    主成分分析(PCA)实现

    参数:
        n_components: int, 要保留的主成分数量
    """

    def __init__(self, n_components):
        self.n_components = n_components
        self.components = None  # 主成分(特征向量)
        self.mean = None  # 数据的均值
        self.explained_variance = None  # 解释方差(特征值)

    def fit(self, X):
        """
        拟合PCA模型

        参数:
            X: numpy数组, 形状为(n_samples, n_features), 输入数据
        """
        # 1. 中心化数据(减去均值)
        self.mean = np.mean(X, axis=0)
        X_centered = X - self.mean

        # 2. 计算协方差矩阵
        cov_matrix = np.cov(X_centered, rowvar=False)

        # 3. 计算特征值和特征向量
        eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

        # 4. 对特征值和特征向量按特征值降序排序
        idx = eigenvalues.argsort()[::-1]
        eigenvalues = eigenvalues[idx]
        eigenvectors = eigenvectors[:, idx]

        # 5. 存储前n_components个主成分和解释方差
        self.components = eigenvectors[:, :self.n_components]
        self.explained_variance = eigenvalues[:self.n_components]

    def transform(self, X):
        """
        将数据转换到主成分空间

        参数:
            X: numpy数组, 形状为(n_samples, n_features), 输入数据

        返回:
            X_transformed: numpy数组, 降维后的数据
        """
        X_centered = X - self.mean
        return np.dot(X_centered, self.components)

    def fit_transform(self, X):
        """
        拟合模型并转换数据

        参数:
            X: numpy数组, 形状为(n_samples, n_features), 输入数据

        返回:
            X_transformed: numpy数组, 降维后的数据
        """
        self.fit(X)
        return self.transform(X)

    def explained_variance_ratio(self):
        """
        计算每个主成分的解释方差比例

        返回:
            numpy数组, 每个主成分解释的方差比例
        """
        return self.explained_variance / np.sum(self.explained_variance)





# 示例使用
if __name__ == "__main__":

    D=pd.read_csv('student_exam_scores.csv')
    print("原始数据形状:", D.shape)
    X=D[["hours_studied","sleep_hours","attendance_percent","previous_scores","exam_score"]]

    # 应用PCA
    pca = PCA(n_components=2)
    X_pca = pca.fit_transform(X)



    print("降维后数据形状:", X_pca.shape)
    print("解释方差比例:", pca.explained_variance_ratio())
    print("累计解释方差：", pca.explained_variance_ratio())
